"""
deepseek_api.py 模块
通过API调用DeepSeek模型的实现（适配BaseLLM基类）
"""
import json
import logging
import os
import ssl  # SSL配置
from typing import Optional, List, Dict
import requests
from requests.adapters import HTTPAdapter
from urllib3.poolmanager import PoolManager  # 连接池管理

# 抑制SSL警告（可选，若证书仍有问题可保留）
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

from src.llm.base_llm import BaseLLM


# 自定义适配器：强制加载系统信任的根证书（解决SSL验证问题）
class SystemCertAdapter(HTTPAdapter):
    def init_poolmanager(self, *args, **kwargs):
        # 强制使用Windows系统的证书库
        context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
        context.load_default_certs()  # 加载系统信任的所有证书
        kwargs['ssl_context'] = context  # 注入SSL上下文
        return super().init_poolmanager(*args, **kwargs)


class DeepSeekAPI(BaseLLM):
    def __init__(
            self,
            api_key: str,
            # 1. 修正：base_url 仅保留根域名（去掉末尾的 /v1）
            base_url: str = "https://api.deepseek.com",
            temperature: float = 0.7,
            max_new_tokens: int = 1024
    ):
        super().__init__(
            # 2. 确认模型名！DeepSeek 官方模型名需对应（如 deepseek-chat-pro 或 deepseek-r1）
            model_name="deepseek-chat",
            temperature=temperature,
            max_tokens=max_new_tokens
        )

        self.api_key = api_key
        self.base_url = base_url
        # 3. 显式拼接 /v1 路径，避免重复
        self.chat_completions_url = f"{self.base_url}/v1/chat/completions"

        if not self.api_key:
            raise ValueError("DeepSeek API密钥不能为空，请在.env中配置DEEPSEEK_API_KEY")

        self.headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {self.api_key}"
        }

        # 关键：绑定自定义适配器，强制HTTPS请求使用系统证书
        self.session = requests.Session()
        self.session.mount("https://", SystemCertAdapter())
        logging.info("DeepSeek API客户端初始化完成（启用系统证书验证）")

    def generate(self, prompts: List[str], stop: Optional[List[str]] = None) -> Dict:
        if not prompts:
            raise ValueError("提示词列表不能为空")

        # 拼接多轮提示词（单轮取第一个，多轮用换行连接）
        prompt = prompts[0] if len(prompts) == 1 else "\n\n".join(prompts)

        payload = {
            "model": self.model_name,
            "messages": [{"role": "user", "content": prompt}],
            "temperature": self.temperature,
            "max_tokens": self.max_tokens,
            "stop": stop or []
        }

        try:
            response = self.session.post(
                url=self.chat_completions_url,
                headers=self.headers,
                json=payload,
                timeout=60  # 超时时间可根据网络调整
            )
            response.raise_for_status()  # 触发HTTP错误捕获
            result = response.json()

            return {
                "generations": [
                    [{"text": result["choices"][0]["message"]["content"].strip()}]
                ]
            }

        # 增强错误处理：区分HTTP错误和其他异常
        except requests.exceptions.HTTPError as e:
            # 处理response可能为None的情况（如连接超时）
            status_code = response.status_code if response else "无（连接失败）"
            response_text = response.text if response else ""
            error_msg = (
                f"API请求失败（状态码：{status_code}）：{str(e)}\n"
                f"请求体：{json.dumps(payload, ensure_ascii=False)}\n"
                f"响应内容：{response_text}"
            )
            logging.error(error_msg)
            raise ValueError(error_msg)

        except Exception as e:
            error_msg = f"调用DeepSeek API时出错：{str(e)}"
            logging.error(error_msg)
            raise ValueError(error_msg)

    def chat(
        self,
        messages: List[dict[str, str]],
        stop: Optional[List[str]] = None
    ) -> str:
        payload = {
            "model": self.model_name,
            "messages": messages,
            "temperature": self.temperature,
            "max_tokens": self.max_tokens,
            "stop": stop or []
        }

        try:
            response = self.session.post(
                url=self.chat_completions_url,
                headers=self.headers,
                json=payload,
                timeout=60
            )
            response.raise_for_status()
            result = response.json()
            return result["choices"][0]["message"]["content"].strip()

        except Exception as e:
            logging.error(f"多轮对话API调用失败：{str(e)}")
            raise